package com.zc.trendsDispatch.task;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.StringUtils;
import com.zc.common.constant.RedisKeyConstants;
import com.zc.iotDevice.domain.ChargeStationPile;
import com.zc.iotDevice.service.impl.ChargeStationPileServiceImpl;
import com.zc.operator.domain.ChargeStation;
import com.zc.operator.mapper.ChargeStationMapper;
import com.zc.remoteControl.service.RemoteInstructSendService;
import com.zc.trendsDispatch.domain.*;
import com.zc.trendsDispatch.mapper.*;
import com.zc.util.ArithmeticUtils;
import org.springframework.stereotype.Component;
import weka.classifiers.Classifier;
import weka.classifiers.functions.LinearRegression;
import weka.core.*;


import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;

import static cn.hutool.core.math.Calculator.conversion;
import static com.zc.util.CommonUtil.localDateToDate;
import static com.zc.util.CommonUtil.localDateToString;
import static com.zc.util.RadixUtil.hexToDecimal;

/**
 * @Author glb
 * @Date 2024/5/9 14:19
 * @Version 1.0
 */

@Component("ChargeStationForecastTask")
public class ChargeStationForecastTask {

    @Resource
    private RemoteInstructSendService remoteInstructSendService;

    @Resource
    private ChargeStationStrategyMapper chargeStationStrategyMapper;

    @Resource
    private ChargeStationStrategyAssociationMapper chargeStationStrategyAssociationMapper;

    @Resource
    private ChargeStationPileServiceImpl chargeStationPileService;

    @Resource
    private ChargeStationCollectionMapper chargeStationCollectionMapper;

    @Resource
    private ChargeStationMapper chargeStationMapper;

    @Resource
    private ChargeStationPredictionMapper chargeStationPredictionMapper;

    @Resource
    private ChargeEngineRuleMapper chargeEngineRuleMapper;


    @Resource
    private RedisCache redisCache;

    private static final String functionId="sendInstruct";

    private static final SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    static class DataRow {
        String time;
        double value;
        //double temp;

        DataRow(String time, double value) {
            this.time = time;
            this.value = value;
            //this.temp = temp;
        }
    }

    public void send(){
        LocalDate todayTime = LocalDate.now();
        Date todayDate = localDateToDate(todayTime);
        String format = dateFormat.format(new Date());
        String substring = format.substring(11, 16);
        if("0".equals(substring.substring(0,1))){
            substring=substring.substring(1);
        }
        System.err.println("substring:"+substring);
        //substring="11:45";
        ChargeStationPrediction chargeStationPrediction=new ChargeStationPrediction();
        chargeStationPrediction.setForecastDate(todayDate);
        //预测列表
        List<ChargeStationPrediction> chargeStationPredictions = chargeStationPredictionMapper.selectChargeStationPredictionList(chargeStationPrediction);
        for (int i = 0; i < chargeStationPredictions.size(); i++) {
            //预测值
            String forecastValue = chargeStationPredictions.get(i).getForecastValue();
            JSONObject jsonObject = JSONObject.parseObject(forecastValue);
            Map<String, Object> personMap = BeanUtil.beanToMap(jsonObject.get(substring));
            String stationCode = chargeStationPredictions.get(i).getStationCode();
            //包边值
            int max= Integer.parseInt(String.valueOf(personMap.get("max")));
            System.err.println("预测值："+personMap.get("value"));
            System.err.println("包边值："+personMap.get("max"));
            //查询场站策略列表
            List<ChargeStationStrategy> chargeStationStrategies = chargeStationStrategyMapper.selectChargeStationStrategyListByCode(stationCode);
            if(chargeStationStrategies.size()>0){
                ChargeStationStrategy chargeStationStrategy = chargeStationStrategies.get(0);
                ChargeEngineRule chargeEngineRule = chargeEngineRuleMapper.selectChargeEngineRuleByRuleId(Long.valueOf(chargeStationStrategies.get(i).getStrategyType()));
                String ruleContent = chargeEngineRule.getRuleContent();
                JSONObject ruleJSONObject = JSONObject.parseObject(ruleContent);
                if (StringUtils.isNotNull((ruleJSONObject))) {
                    List<ChargeRuleTrigger> triggers = JSONObject.parseArray(ruleJSONObject.getString("trigger"), ChargeRuleTrigger.class);
                    //变压器容量
                    int transformerCapacity = chargeStationStrategy.getTransformerCapacity();
                    //阈值
                    int threshold = chargeStationStrategy.getThreshold();
                    //变压器容量-阈值=可用容量
                    double available = ArithmeticUtils.sub(transformerCapacity, threshold);
                    //可用容量-预测包边值=充电桩可分配值
                    double reality = ArithmeticUtils.sub(available, max);
                    //设置功率16进制
                    String setValue = ChargeStationStrategyTask.conversion(triggers, reality);
                    ChargeStationPile chargeStationPile=new ChargeStationPile();
                    chargeStationPile.setStationCode(stationCode);
                    chargeStationPile.setStatus("1");
                    //根据场站查询充电桩数
                    List<ChargeStationPile> listPile = chargeStationPileService.getList(chargeStationPile);
                    listPile.forEach(pile->{
                        JSONArray deviceArr =new JSONArray();
                        JSONObject  subclassProperties = new JSONObject (true);
                        subclassProperties.put("deviceCode",pile.getDeviceId());
                        subclassProperties.put("forecastValue",personMap.get("value"));
                        subclassProperties.put("setValue",setValue);
                        subclassProperties.put("forecastTime",dateFormat.format(new Date()));
                        deviceArr.add(subclassProperties);
                        JSONObject  properties = new JSONObject (true);
                        properties.put("stationCode",stationCode);
                        properties.put("type","4");
                        properties.put("meter",deviceArr);
                        System.err.println("下发参数："+properties.toJSONString());
                        remoteInstructSendService.sendMessage(pile.getDeviceId() + "-1", functionId, properties);
                    });

                }
            }
        }

        /*SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String forecastTime = dateFormat.format(new Date());
        String deviceCode="44030900020002";
        String stationCode="1004";
        String forecastValue="30";
        String setValue="100";
        JSONObject  subclassProperties = new JSONObject (true);
        subclassProperties.put("deviceCode",deviceCode);
        subclassProperties.put("forecastValue",forecastValue);
        subclassProperties.put("setValue",setValue);
        subclassProperties.put("forecastTime",forecastTime);
        JSONArray deviceArr =new JSONArray();
        deviceArr.add(subclassProperties);
        JSONObject  properties = new JSONObject (true);
        properties.put("stationCode",stationCode);
        properties.put("type","4");
        properties.put("meter",deviceArr);
        remoteInstructSendService.sendMessage(deviceCode + "-1", functionId, properties);*/
    }

    public void collection() throws ParseException {
        Date date = new Date();
        SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat year= new SimpleDateFormat("yyyy-MM-dd");
        String format = dateFormat.format(date);
        String substring = format.substring(11, 16);
        if("0".equals(substring.substring(0,1))){
            substring=substring.substring(1);
        }
        List<ChargeStationStrategy> chargeStationStrategyList = chargeStationStrategyMapper.selectChargeStationStrategyList(new ChargeStationStrategy());
        String finalSubstring = substring;
        chargeStationStrategyList.forEach(strategy->{
            ChargeStationStrategyAssociation chargeStationStrategyAssociation=new ChargeStationStrategyAssociation();
            chargeStationStrategyAssociation.setStationId(strategy.getStationCode());
            //总表功率
            double countPower=0;
            List<ChargeStationStrategyAssociation> chargeStationStrategyAssociations = chargeStationStrategyAssociationMapper.selectChargeStationStrategyAssociationList(chargeStationStrategyAssociation);
            for (int i1 = 0; i1 < chargeStationStrategyAssociations.size(); i1++) {
                Object cacheMapValue = redisCache.getCacheMapValue(RedisKeyConstants.STATION_DEVICE_REAL_POWER.replaceAll(":station:device", ":"+strategy.getStationCode()+""), chargeStationStrategyAssociations.get(i1).getDeviceId());
                if(cacheMapValue!=null){
                    countPower = ArithmeticUtils.add(countPower, Double.parseDouble(cacheMapValue.toString()));
                }
            }

            int transformerCapacity = strategy.getTransformerCapacity();
            int threshold = strategy.getThreshold();
            //可用阈值（变压器容量-变压器阈值）
            double available = ArithmeticUtils.sub(transformerCapacity, threshold);
            //充电桩功率
            double pilePower=0;
            ChargeStationPile chargeStationPile=new ChargeStationPile();
            chargeStationPile.setStationCode(strategy.getStationCode());
            chargeStationPile.setStatus("1");
            List<ChargeStationPile> listPile = chargeStationPileService.getList(chargeStationPile);
            for (int i = 0; i < listPile.size(); i++) {
                String deviceId = listPile.get(0).getDeviceId();
                for (int j = 1; j <3 ; j++) {
                    deviceId=deviceId.replaceAll("-1","");
                    String gunCode=deviceId+"0"+j+"-1";
/*                    Map<String, DeviceProperty> realData = remoteInstructSendService.getRealData(gunCode);
                    if (realData.containsKey("outP") ) {
                        double outP = Double.parseDouble(String.valueOf(realData.get("outP").getValue()));
                        pilePower=ArithmeticUtils.add(pilePower,outP);
                    }*/
                    Object cacheMapValue = redisCache.getCacheMapValue(RedisKeyConstants.STATION_PILE_REAL_POWER.replaceAll(":station:pile", ":"+strategy.getStationCode()+""),gunCode);
                    if(cacheMapValue!=null){
                        pilePower = ArithmeticUtils.add(pilePower, Double.parseDouble(cacheMapValue.toString()));
                    }
                }

            }
            //负载功率
            double loadPower = ArithmeticUtils.sub(countPower, pilePower);
            System.out.println("可用阈值:"+available);
            System.out.println("充电桩功率:"+pilePower);
            System.out.println("总表功率:"+countPower);
            System.out.println("负载功率:"+loadPower);
            ChargeStationCollection chargeStationCollection=new ChargeStationCollection();
            chargeStationCollection.setStationCode(strategy.getStationCode());
            try {
                chargeStationCollection.setCollectionDate(year.parse(format.substring(0,10)));
            } catch (ParseException e) {
                e.printStackTrace();
            }
            List<ChargeStationCollection> chargeStationCollections = chargeStationCollectionMapper.selectChargeStationCollectionList(chargeStationCollection);
            Map<String, Object> personMap=new LinkedHashMap<>();
            personMap.put("time", finalSubstring);
            personMap.put("transformerCapacity", transformerCapacity);
            personMap.put("threshold", threshold);
            personMap.put("available", available);
            personMap.put("countPower", countPower);
            personMap.put("pilePower", pilePower);
            personMap.put("loadPower", loadPower);
            if(chargeStationCollections.size()>0){
                ChargeStationCollection stationCollection = chargeStationCollections.get(0);
                JSONObject jsonObject = JSONObject.parseObject(stationCollection.getCollectionValue());
                jsonObject.put(finalSubstring,personMap);
                stationCollection.setCollectionValue(jsonObject.toJSONString());
                chargeStationCollectionMapper.updateChargeStationCollection(stationCollection);
            }else{
                JSONObject jsonObject =new JSONObject(true);
                jsonObject.put(finalSubstring,personMap);
                chargeStationCollection.setCollectionValue(jsonObject.toJSONString());
                chargeStationCollectionMapper.insertChargeStationCollection(chargeStationCollection);
            }
        });
    }

    public void forecast(){
        // 获取当前日期
        LocalDate todayTime = LocalDate.now();
        //训练数据日期
        LocalDate trainTime  = todayTime.minus(5, ChronoUnit.DAYS);
        //比较数据日期
        LocalDate compareTime = todayTime.minus(1, ChronoUnit.DAYS);
        String todayTimeString = localDateToString(todayTime, "yyyy-MM-dd");
        String trainTimeString = localDateToString(trainTime, "yyyy-MM-dd");
        String compareTimeString = localDateToString(compareTime, "yyyy-MM-dd");
        List<ChargeStation> chargeStationList = chargeStationMapper.selectChargeStationList(new ChargeStation());
        for (int i = 0; i < chargeStationList.size(); i++) {
            String chargeStationCode = chargeStationList.get(i).getChargeStationCode();
            List<DataRow> trainList=new ArrayList<>();
            List<DataRow> compareList=new ArrayList<>();
            List<ChargeStationCollection> chargeStationCollectionList = chargeStationCollectionMapper.selectChargeStationCollectionListByTime(chargeStationCode, trainTimeString, compareTimeString);
            for (int s = 0; s < chargeStationCollectionList.size(); s++) {
                JSONObject jsonObject = JSONObject.parseObject(chargeStationCollectionList.get(s).getCollectionValue());
                List<DataRow> dataRowList = assemble(jsonObject);
                trainList.addAll(dataRowList);
            }
            ChargeStationCollection chargeStationCollection = chargeStationCollectionMapper.selectChargeStationCollectionListByCollectionDate(chargeStationCode, compareTimeString);
            if(chargeStationCollection!=null){
                JSONObject jsonObject = JSONObject.parseObject(chargeStationCollection.getCollectionValue());
                List<DataRow> dataRowList = assemble(jsonObject);
                compareList.addAll(dataRowList);
            }
            if(trainList.size()>0&&compareList.size()>0){
                try {
                    //训练数据
                    Instances train = trainingPrediction(trainList);
                    //模拟数据
                    Instances imitate = trainingPrediction(compareList);
                    //创建并配置分类器
                    Classifier classifier = new LinearRegression();
                    classifier.buildClassifier(train);

                    List<Map<String,Object>> list=new ArrayList<>();
                    for (int k = 0; k < imitate.numInstances(); k++) {
                        Map<String,Object> map=new HashMap();
                        Instance testInstance = imitate.instance(k);
                        //输出预测结果
                        double prediction = classifier.classifyInstance(testInstance);
                        //预测时间段
                        String time =testInstance.toString(0);
                        //比较值
                        double compareValue = testInstance.classValue();
                        //预测结果处理
                        prediction= Double.parseDouble(ArithmeticUtils.accurateDecimal(String.valueOf(ArithmeticUtils.add(prediction,8)),2));
                        map.put("time",time);
                        map.put("value",prediction);
                        list.add(map);
                    }
                    handle(chargeStationCode,localDateToDate(todayTime),list);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        }


    }



    public  void handle(String stationCode,Date forecastDate,List<Map<String,Object>> list){
        JSONObject result = new JSONObject(true);
        for (int i = 0; i < list.size(); i++) {
            Double max = Double.valueOf(String.valueOf(list.get(i).get("value")));
            String time = String.valueOf(list.get(i).get("time"));
            if (max <= 30) {
                list.get(i).put("max",30);
                if(i!=0){
                    String o = String.valueOf(list.get(i-1).get("max"));
                    String change = change(o, "30");
                    list.get(i).put("change",change);
                    list.get(i).put("reality",max-8);
                }else{
                    list.get(i).put("change",0);
                    list.get(i).put("reality",max-8);

                }
                result.put(time, list.get(i));
            } else if (max <= 60) {
                list.get(i).put("max",60);
                if(i!=0){
                    String o = String.valueOf(list.get(i-1).get("max"));
                    String change = change(o, "60");
                    list.get(i).put("change",change);
                    list.get(i).put("reality",max-8);

                }else{
                    list.get(i).put("change",0);
                    list.get(i).put("reality",max-8);
                }
                result.put(time, list.get(i));
            } else if (max <= 90) {
                list.get(i).put("max",90);
                if(i!=0){
                    String o = String.valueOf(list.get(i-1).get("max"));
                    String change = change(o, "90");
                    list.get(i).put("change",change);
                    list.get(i).put("reality",max-8);
                }else{
                    list.get(i).put("change",0);
                    list.get(i).put("reality",max-8);
                }
                result.put(time, list.get(i));
            } else if (max <= 120) {
                list.get(i).put("max",120);
                if(i!=0){
                    String o = String.valueOf(list.get(i-1).get("max"));
                    String change = change(o, "120");
                    list.get(i).put("change",change);
                    list.get(i).put("reality",max-8);
                }else{
                    list.get(i).put("change",0);
                    list.get(i).put("reality",max-8);
                }
                result.put(time, list.get(i));
            } else if (max <= 150) {
                list.get(i).put("max",150);
                if(i!=0){
                    String o = String.valueOf(list.get(i-1).get("max"));
                    String change = change(o, "150");
                    list.get(i).put("change",change);
                    list.get(i).put("reality",max-8);
                }else{
                    list.get(i).put("change",0);
                    list.get(i).put("reality",max-8);
                }
                result.put(time, list.get(i));
            }
        }
        ChargeStationPrediction chargeStationPrediction=new ChargeStationPrediction();
        chargeStationPrediction.setStationCode(stationCode);
        chargeStationPrediction.setForecastDate(forecastDate);
        List<ChargeStationPrediction> chargeStationPredictionList = chargeStationPredictionMapper.selectChargeStationPredictionList(chargeStationPrediction);
        if(chargeStationPredictionList.size()>0){
            chargeStationPredictionMapper.deleteChargeStationPredictionByStationCode(stationCode,forecastDate);
        }
        chargeStationPrediction.setForecastValue(result.toJSONString());
        chargeStationPredictionMapper.insertChargeStationPrediction(chargeStationPrediction);
        System.out.println("预测结果集合:"+result.toJSONString());
    }

    public  List<DataRow> assemble(JSONObject data){
        List<DataRow> mergeList=new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        for (Object key : data.keySet()) {
            map.put((String) key, data.get(key));
        }
        List<Map.Entry<String, Object>> sortedEntries = new ArrayList<>(map.entrySet());
        sortedEntries.sort(Map.Entry.comparingByKey());
        // 打印排序后的结果
        for (Map.Entry<String, Object> entry : sortedEntries) {
            Map<String, Object> personMap = BeanUtil.beanToMap(entry.getValue());
            String time= String.valueOf(personMap.get("time"));
            Double loadPower= Double.valueOf(String.valueOf(personMap.get("loadPower")));
            DataRow dataRow=new DataRow(time,loadPower);
            mergeList.add(dataRow);
        }

        return mergeList;
    }

    public  Instances trainingPrediction(List<DataRow> data) {
        Attribute time = createTimeAttribute();
        Attribute temp = new Attribute("temp");
        Attribute power = new Attribute("power");
        FastVector<Attribute> attributes = new FastVector<Attribute>();
        attributes.addElement(time);
        attributes.addElement(temp);
        attributes.addElement(power);
        // 创建 Instances 对象
        Instances dataset = new Instances("data", attributes, 0);
        dataset.setClassIndex(dataset.numAttributes() - 1);
        // 添加数据
        addDataToInstances(dataset,data);
        dataset.setClassIndex(2);
        return dataset;

    }

    private  void addDataToInstances(Instances dataset,List<DataRow> data) {
        data.forEach(d->{
            dataset.add(createInstance(d.time, d.value, dataset));
        });
    }

    private static Instance createInstance(String timeValue, double power, Instances dataset) {
        DenseInstance instance = new DenseInstance(3);
        instance.setDataset(dataset);
        if(timeValue.length()<5){
            timeValue="0"+timeValue;
        }
        instance.setValue(0, timeValue);
        //instance.setValue(1, temp);
        instance.setValue(2, power);
        return instance;
    }

    private static Attribute createTimeAttribute() {
        FastVector<String> timeValues = new FastVector<String>();
        for (int hour = 0; hour < 24; hour++) {
            for (int minute = 0; minute < 60; minute += 5) {
                String timeString = String.format("%02d:%02d", hour, minute);
                timeValues.addElement(timeString);
            }
        }
        Attribute time = new Attribute("time", timeValues);
        return time;
    }

    public  String change(String newValue, String oldValue){
        if(newValue.equals(oldValue)){
            return "0";
        }else {
            return "1";
        }

    }


    public static void main(String[] args) {

    }
}
